#include "TcpConnection.h"
#include "EventLoop.h"

using std::cout;
using std::endl;

TcpConnection::TcpConnection(int fd,EventLoop *loop) 
:_loop(loop)
,_socketIO(fd)
,_sock(fd)
,_localAddr(getLocalAddr())
,_peerAddr(getPeerAddr())
{}

TcpConnection::~TcpConnection() {}

void TcpConnection::send(const string & msg) {
    _socketIO.writen((char*)msg.c_str(),strlen(msg.c_str()));
    return;
}

string TcpConnection::receive() {
    char buf[65535] = {0};
    _socketIO.readLine(buf,sizeof(buf));
    return string(buf);
}

void TcpConnection::sendTrain(const train_t& train){
    _socketIO.writeTrain(train);
    return ;
}

void TcpConnection::recvTrain(train_t& train){
    _socketIO.readTrain(train);
    return ;
}

bool TcpConnection::isClosed(){
    char buf[4096] = {0};
    int ret = recv(_sock.fd(),buf,sizeof(buf),MSG_PEEK);
    
    return (0 == ret);
}

InetAddress TcpConnection::getLocalAddr(){
    struct sockaddr_in localAddr;
    socklen_t addrlen = sizeof(localAddr);
    int ret = ::getsockname(_sock.fd(),(struct sockaddr*)&localAddr,&addrlen);
    if(-1 == ret){
        perror("getsockname");
        exit(1);
    }
    return InetAddress(localAddr);
}

InetAddress TcpConnection::getPeerAddr(){
    struct sockaddr_in peerAddr;
    socklen_t addrlen = sizeof(peerAddr);
    int ret = ::getpeername(_sock.fd(),(struct sockaddr*)&peerAddr,&addrlen);
    if(-1 == ret){
        perror("getpeername");
        exit(1);
    }
    return InetAddress(peerAddr);
}

string TcpConnection::toString(){
    ostringstream oss;
    oss << _localAddr.ip() << "::" << _localAddr.port();
    oss << "-------->";
    oss << _peerAddr.ip() << "::" << _peerAddr.port();
    return oss.str();
}

void TcpConnection::setNewConnectionCallback(const TcpConnectionCallback &cb){
    _onNewConnectionCb = cb;
} 
void TcpConnection::setMessageCallback(const TcpConnectionCallback &cb){
    _onMessageCb = cb;
}
void TcpConnection::setCloseCallback(const TcpConnectionCallback &cb){
    _onCloseCb = cb;
}

void TcpConnection::handleNewConnectionCallback(){
    if(_onNewConnectionCb){
        //不能直接传入this指针，那样会导致生成一个临时的shared_ptr托管this指针，引起double free
        /* _onNewConnectionCb(shared_ptr<TcpConnection>(this)); */
        _onNewConnectionCb(shared_from_this());
    }else{
        cout << "_onNewConnectionCb == nullptr" << endl;
    }
}

void TcpConnection::handleMessageCallback(){
    if(_onMessageCb){
        _onMessageCb(shared_from_this());
    }else{
        cout << "_onMessageCb == nullptr" << endl;
    }
}

void TcpConnection::handleCloseCallback(){
    if(_onCloseCb){
        _onCloseCb(shared_from_this());
    }else{
        cout << "_onCloseCb == nullptr" << endl;
    }
}

//此处的sendInLoop中的函数的形参msg是线程池处理好
//之后的,可以发给Reactor/EventLoop的数据。
//但是对于EventLoop/Reactor而言，即使拿到了处理好
//之后的数据msg,也不能将数据发送给客户端，因为对于
//EventLoop/Reactor而言，它本身没有发送数据的能力
//
//真正在整个设计中，具备发送数据能力的类有两个 一个
//是TcpConnection，另一个是SocketIO,而SocketIO更偏向
//底层，真正对外发送数据的其实就是TcpConnection对象，
//或者更具体的说，就是TcpConnection中的send函数。
//所以需要将具有发送数据能力的TcpConnection中的send
//函数,以及要发送的数据msg一起打包成"任务"交给EventLoop/Reactor
//,这样EventLoop/Reactor就可以将数据发给客户端。
void TcpConnection::sendInLoop(const string& msg){
    function<void()> f = bind(&TcpConnection::send,this,msg);
    if(_loop){
        //void runInLoop(function<void()> &&cb)
        _loop->runInLoop(std::move(f));
        /* f(); */
    }

}

void TcpConnection::sendTrainInLoop(const train_t& train){
    function<void()> f = bind(&TcpConnection::sendTrain,this,train);
    if(_loop){
        //void runInLoop(function<void()> &&cb)
        _loop->runInLoop(std::move(f));
        /* f(); */
    }

}
